// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: tianqiang

#pragma once

#include <string>

#include "coin/proto/coin_order_enums.pb.h"
#include "coin2/exchange/base/order/parser.h"
#include "coin2/exchange/mexc/api_order_v3/native_private_client.h"
#include "coin2/exchange/mexc/symbology_v3/currency.h"

namespace coin2::exchange::mexc::order_v3 {

class MexcParser : public base::order::BaseParser {
  using JsonValue = base::order::BaseParser::JsonValue;
  using ProductOrderBundle = base::order::BaseParser::ProductOrderBundle;
  using ProductFillBundle = base::order::BaseParser::ProductFillBundle;
  using AccountBalance = base::order::BaseParser::AccountBalance;
  using ProductOrderElement = base::order::BaseParser::ProductOrderElement;
  using ProductFillElement = base::order::BaseParser::ProductFillElement;
  using OrderErrorCode = base::order::BaseParser::OrderErrorCode;
  using OrderSubTopicId = base::order::BaseParser::OrderSubTopicId;
  using OrderSide = coin::proto::OrderSide;
  using OrderType = coin::proto::OrderType;
  using FillType = coin::proto::FillType;
  using TransferRequestProto = coin::proto::TransferRequestProto;
  using MexcOrderSubTopicId = coin2::exchange::mexc::api_order_v3::MexcOrderSubTopicId;
  using MexcCurrency = coin2::exchange::mexc::symbology_v3::MexcCurrency;

 public:
  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  AccountBalance ParseBalance(const JsonValue& doc) override;
  bool ParseRawBalance(const JsonValue& doc, RawBalanceMap* raw_balance_map);

 private:
  void ParseSubmitResponse();
  void ParseBatchSubmitResponse();
  void ParseCancelResponse();
  void ParseRestAccountBalance();
  void ParseRestOpenOrderInfo();
  void ParseRestAllOrderInfo();
  void ParseRestFillOrderInfo();
  void ParseListenKey();

  void ParseWsOrderInfo(const JsonDocument& document);
  void ParseWsDealsInfo(const JsonDocument& document);
  void ParseWsBalanceInfo(const JsonDocument& document);
  void ParseWsMessage();

  void ParseRestOrder(const JsonValue& data, ProductOrderElement* product_order_element);
  void ParseRestFill(const JsonValue& data, ProductFillElement* product_fill_element);

  std::optional<std::string> GetMsg(const JsonValue& data) const;
  std::optional<int64_t> GetCode(const JsonValue& data) const;
  bool IsMexcSpotErrMessage(const JsonValue& data) const;
  OrderErrorCode GetOrderErrorCode(int64_t code);
  int64_t ParseProcOrderId(const std::string& proc_order_id) const;
  int64_t GetProcOrderId(const JsonValue& data) const;
  int64_t GetWsProcOrderId(const JsonValue& data) const;
  OrderSide GetOrderSide(const std::string& side) const;
  OrderSide GetWsOrderSide(const std::string& side) const;
  OrderType GetOrderType(const std::string& type) const;
  OrderType GetWsOrderType(const std::string& type) const;
  void ParseRestDeposit();
  void ParseRestWithdrawal();
  void ParseTransfer(std::string account_into);
  void SetOrderStatus(const std::string& status, ProductOrderElement* product_order_element);
  void SetWsOrderStatus(const std::string& status, ProductOrderElement* product_order_element);

  // bool LoadZombieOrderCheckList(const std::string& mixin_order_ids);
  // void CheckZombieOrder(ProductOrderBundle* product_order_bundle);

  int32_t ParseErrorMessage(const std::shared_ptr<AsioHttpContext>& http_context);

 private:
  std::unordered_map<std::string, std::vector<int64_t>> mixin_zombie_order_ids_map_;

  bool is_account_balance_initialized_ = false;
  std::map<std::string, int> transfer_deposit_map_;
  bool is_transfer_deposit_initialized_ = false;
  std::map<std::string, int> transfer_withdrawal_map_;
  bool is_transfer_withdrawal_initialized_ = false;
  std::map<std::string, int> transfer_id_map_;

  std::set<std::string> transfer_account_info_set_;
};

}  // namespace coin2::exchange::mexc::order_v3
